<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>this绑定之外的情况(Situations outside of this binding)</title>
  <!-- 
  在JavaScript中，this关键字的绑定通常遵循一系列规则，包括默认绑定、隐式绑定、显式绑定等。然而，也有一些特殊情况会导致this的行为与这些规则不同。
  一、箭头函数
  - 定义：箭头函数没有自己的this，它会从定义时的上下文中继承this。这意味着在箭头函数内，this的值是由外部函数的this决定的。
    const obj = {
      name: 'Alice',
      showName: function() {
        const arrowFunc = () => {
          console.log(this.name); // 这里的this指向obj
        };
        arrowFunc();
      }
    };

    obj.showName(); // 输出: Alice

  二、事件处理程序
  - 定义：在事件处理程序中，this的值通常指向触发事件的元素，而不是定义该事件处理程序的对象。
    const button = document.getElementById('myButton');
    button.addEventListener('click', function() {
      console.log(this); // 输出: <button id="myButton">...</button>
    });

  三、setTimeout 和 setInterval
  - 定义：在setTimeout和setInterval的回调函数中，this的值会默认绑定到全局对象（在浏览器中为window），而不是调用它的对象。
    const obj = {
      name: 'Alice',
      showName: function() {
        setTimeout(function() {
          console.log(this.name); // 输出: undefined
        }, 1000);
      }
    };

    obj.showName();

  四、使用 call、apply 和 bind
  - 定义：这三个方法可以显式地绑定this，即使在函数定义的上下文中没有明确绑定。它们允许开发者指定this的值。
    function showName() {
      console.log(this.name);
    }

    const obj = { name: 'Alice' };
    showName.call(obj); // 输出: Alice

  五、严格模式
  - 定义：在严格模式下，未绑定的函数调用的this为undefined，而不是全局对象。这会影响一些默认绑定的行为。
    "use strict";

    function showThis() {
      console.log(this);
    }
    showThis(); // 输出: undefined

  六、总结
  1. 箭头函数：没有自己的this，继承自外部上下文。
  2. 事件处理程序：this指向触发事件的元素。
  3. setTimeout 和 setInterval：this默认指向全局对象。
  4. 显式绑定：使用call、apply和bind方法可以手动设置this的值。
  5. 严格模式：未绑定的函数调用的this为undefined。
   -->
</head>
<body>

  <script>
    // 1. 显示绑定null/undefined, this指向window等于(默认绑定)
    function foo() {
      console.log("foo:", this);
    }

    foo.apply("apply")
    foo.apply(null)
    foo.apply(undefined)

    // 2. 箭头函数
    const obj = {
      name: 'Alice',
      showName: function() {
        setTimeout(() => {
          console.log(this.name); // 输出: Alice
        }, 1000);
      }
    };

    obj.showName();

    // 3. 间接函数引用
    const obj1 = {
      name: 'Bob',
      foo: function() {
        console.log("obj1:", this, "this.name=", this.name);
      }
    }
    const obj2 = {
      name: 'Charlie',
    }    
    
    // {}[]()
    obj2.foo = obj1.foo;
    obj2.foo(); // 输出: Charlie

    (obj2.foo = obj1.foo)(); // 输出: window

    
  </script>
  
</body>
</html>